package com.crl.ui.controls {
	import flash.display.*;
	import flash.net.*;
	import flash.text.engine.*;
	import flash.utils.*;
	
	
	/**
	 * 
	 * @author crl
	 * 
	 * project http://code.google.com/p/smiletext/
	 * ex:
	 * var emoticons:Dictionary = new Dictionary();
	 *	emoticons[":)"] = HappyIcon;
	 *	emoticons[";)"] = SmileIcon;
	 *	
	 *	var st:SmileText = new SmileText(emoticons);
	 *	st.font = new FontDescription("Arial");
	 *	st.text = "Voici un texte qui contient :) un smiley \net en voici un autre ;) plus sympa non";
	 *	addChild(st);
	 * 
	 */	
	public class SmileText extends Sprite {
		public var smileCodes:String;
		private var _text:String;
		private var _emoticons:Dictionary;
		private var _font:FontDescription;
		private var __width:Number;
		private var _gap:int = 5;
		
		public function get gap():int {
			return _gap;
		}
		
		public function set gap(value:int):void {
			if(value != gap) {
				_gap = value;
				
				refresh();
			}
		}
		
		public override function get width():Number {
			return __width;
		}
		
		public override function set width(value:Number):void {
			if(value != width) {
				__width = value;
				
				refresh();
			}
		}
		
		public function get font():FontDescription {
			return _font;
		}
		
		public function set font(value:FontDescription):void {
			if(value != _font) {
				_font = value;
				
				refresh();
			}
		}
		
		public function get text():String {
			return _text;
		}
		
		public function set text(value:String):void {
			if(value != text) {
				_text = value;
				
				refresh();
			}
		}
		
		public function SmileText(emoticons:Dictionary = null) {
			_emoticons = emoticons != null ? emoticons : new Dictionary();
			_font = new FontDescription();
			
			createSmileCodes();
		}
		
		protected function render():void {
			if(text) {
				var gp:GroupElement = createGroupElements();
				var tb:TextBlock = new TextBlock();
				tb.content = gp;
				createLines(tb);
			}
		}
		
		protected function clear():void {
			while (numChildren > 0) {
				removeChildAt(0);
			}
		}
		
		private function createLines(textBlock:TextBlock):void {
			var textLine:TextLine = textBlock.createTextLine(null);
			var yPos:Number = textLine.ascent;
			while(textLine) {
				addChild(textLine);
				textLine.y = yPos;
				yPos += textLine.textHeight + gap;
				textLine = textBlock.createTextLine(textLine);
			}
		}
		
		internal function createGroupElements():GroupElement {
			var format:ElementFormat = new ElementFormat(font);
			
			var vectorGp:Vector.<ContentElement> = new Vector.<ContentElement>();
			var splited:Array = splitText();
			for each(var token:String in splited) {
				var smile:DisplayObject;
				var smileCode:* = _emoticons[token];
				if(smileCode) {
					if(smileCode is String) {
						smile = loadEmoticon(smileCode);
					} else if(smileCode is Class) {
						smile = new smileCode();
					}
					// TODO: position smile for baseline text
					vectorGp.push(new GraphicElement(smile,24,smile.height - getTextBaseLine(),format));
				} else {
					vectorGp.push(new TextElement(token,format));
				}
			}
			return new GroupElement(vectorGp);
		}
		
		internal function createSmileCodes():void {
			var codes:Array = [];
			for(var smile:String in _emoticons) {
				codes.push(escapeRegExp(smile));
			}
			smileCodes = codes.join("|");
			smileCodes = "(" + smileCodes + ")";
		}
		
		internal function escapeRegExp(code:String):String {
			return code.replace(/(\(|\)|\.)/gi,"\\$1");
		}
		
		internal function splitText():Array {
			var pattern:RegExp = new RegExp(smileCodes,"gim");
			var splited:Array = text.split(pattern);
			return splited;
		}
		
		internal function getTextBaseLine():Number {
			var format:ElementFormat = new ElementFormat(font);
			
			var ref:TextElement = new TextElement("Wj",format);
			var tb:TextBlock = new TextBlock();
			tb.content = ref;
			var tl:TextLine = tb.createTextLine(null);
			return tl.ascent;
		}
		
		private function refresh():void {
			clear();
			render();
		}
		
		//TODO: using proxy for loading
		private function loadEmoticon(url:String):Loader {
			var loader:Loader = new Loader();
			loader.load(new URLRequest(url));
			return loader;
		}
	}
}